1

In the addon of the session, we counted the charging stations located within North-Rhine Westphalia (NRW). Still, we did not show how to get a point layer of NRW charging stations (“charger_nrw”).

Subset the data file yourself by relying on the spatial information of the file charging_points_ger.csv and a polygon of NRW. There are two ways to achieve this. How many chargers are located within NRW?
You need two datasets for that: the point layer charging_points_ger.csv (remember to adjust the crs) in the ./data folder and polygons of NRW. For the latter, you can again use the osmdata syntax.

There are two functions you can explore: sf::st_join and sf::st_intersection(). The default of sf::st_join() will leave you with a ‘left-join’ and returns a data object with all chargers and matching district information for those which are located within NRW. You can reset the option to perform an ‘inner-join’ and keep only the observation which lay within the predefined area (sf::st_join(x , y, join = "", left = FALSE)).

# load charger
charger_ger <- 
  # Read charging station points datae
  readr::read_delim("./data/charging_points_ger.csv", 
                                 delim = ";") %>%
  # Filter out rows with missing longitude or latitude
  dplyr::filter(!is.na(longitude) & !is.na(latitude)) %>%
  # Convert data frame to sf object
  sf::st_as_sf(coords = c("longitude", "latitude"), crs = 4326) %>%
  # Reproject the spatial data to the desired CRS (Coordinate Reference System)
  sf::st_transform(crs = 3035) 
## Warning: One or more parsing issues,
## call `problems()` on your
## data frame for details, e.g.:
##   dat <- vroom(...)
##   problems(dat)
## Rows: 60560 Columns: 7
## ── Column specification ──────
## Delimiter: ";"
## chr (3): operator, federal...
## dbl (4): latitude, longitu...
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
#  use the OSM function
nrw <-
  osmdata::getbb(
    "Nordrhein-Westfalen", 
    format_out = "sf_polygon"
  ) %>% 
  .$multipolygon %>% 
  sf::st_transform(3035)

# option 1
charger_nrw <- 
  charger_ger %>% 
  # Subset point data to sampling area
  sf::st_intersection(nrw)
## Warning: attribute variables
## are assumed to be spatially
## constant throughout all
## geometries
# option 2
# spatial join
charger_nrw <-
  charger_ger %>%  
  sf::st_join(
    # point layer nrw
    nrw, 
    # chose intersect or within
    join = sf::st_intersects,
    # option FALSE will 
    # keep only the chargers 
    # which could be joined
    left = FALSE
  )
 
nrow(charger_nrw)
## [1] 11081
# 11081 chargers in NRW

2

Did the operationalization of train station accessbility convince you? The INKAR data base offers another approach: Proportion of residents with max. 1000m linear distance to the nearest public transport stop in the district. We do have everything to create this indicator. You can run this code to load all the data you need. What is the mean share of residents with max. 1000m linear distance to the nearest train station in a 5km neighbourhood of our fake respondents?

nrw <-
  osmdata::getbb(
    "Nordrhein-Westfalen", 
    format_out = "sf_polygon"
  ) %>% 
  .$multipolygon %>% 
  sf::st_transform(3035) 

set.seed(1234)

fake_coordinates <-
  sf::st_sample(nrw, 1000) %>% 
  sf::st_sf() %>% 
  dplyr::mutate(
    id_2 = 
      stringi::stri_rand_strings(10000, 10) %>% 
      sample(1000, replace = FALSE)
  )

nrw_pt_trainstops <- sf::st_read("./data/nrw_pt_osmtrainstops.shp", crs = 3035)

inhabitants_ger <-
  z11::z11_get_100m_attribute(Einwohner) 
As always, there are several ways to do this. Anne tried to keep the workflow as close to the function taught in this course and suggests following steps: 1. Create a point layer with the centroids of all grids in NRW based on the z11 population layer. 2. Calculate the distance to the next train station for each grid. 3. Create a column that equals 0 if the distance to the next train station is >1000m and contains the number of inhabitants if <1000. 4. Rasterize the sf data object to receive two raster object: number of inhabitants and number of inhabitants with max 1000m distance to next train station. 5. Calculate the mean for the 5km buffer for each “respondent” for each raster. 6. Calculate the share.
In the add-on slides of the raster session Stefan introduced gave some information on how to transform raster to points (and back). To get a sf point layer of the raster object you can use terra::as.points() %>% sf::st_as_sf(). To rasterize the object you can use terra::rast(vals = .$colname, resolution = 100).
# Extract inhabitants points for North Rhine-Westphalia (NRW)
nrw_pt_inhabitants <- 
  inhabitants_ger %>% 
  terra::crop(., nrw) %>% 
  # convert to points
  terra::as.points() %>%   
  # convert to sf object
  sf::st_as_sf() 

# Find the nearest train station for each grid centroid
nearest_station <- 
  sf::st_nearest_feature(nrw_pt_inhabitants, nrw_pt_trainstops)

# Calculate distances from inhabitants to the nearest train station
distances <- sf::st_distance(nrw_pt_inhabitants, 
                             nrw_pt_trainstops[nearest_station,], 
                             by_element = TRUE) 

# Create a raster representing population with train access within 1000m for NRW 
nrw_rast_inhabitants_access <- 
  nrw_pt_inhabitants %>% 
  dplyr::mutate(train_access = ifelse(as.numeric(distances) <= 1000, lyr.1, 0)) %>% 
  terra::rast(vals = .$train_access, resolution = 100) 
## Warning: [setValues] values
## were recycled
# Create a raster representing population  for NRW
# NOTE: You could also use the 'old' raster. However, by converting the
# data the extent of the raster layer might not fit anymore and needs adjustments.
nrw_rast_inhabitants <- 
  nrw_pt_inhabitants %>% 
  terra::rast(vals = .$lyr.1, resolution = 100) 
## Warning: [setValues] values
## were recycled
# Extract population within 5km buffers around each respondent
population_buffers <- 
  terra::extract(
    nrw_rast_inhabitants, 
    fake_coordinates %>% 
      sf::st_buffer(5000) %>% 
      terra::vect(), 
    fun = mean,
    na.rm = TRUE
  )

# Extract population within 5km buffers considering train access within 1000m
population_access_buffers <- terra::extract(
  nrw_rast_inhabitants_access, 
  fake_coordinates %>% 
    sf::st_buffer(5000) %>% 
    terra::vect(), 
  fun = mean,
  na.rm = TRUE
)

# Combine population data with train access information
linked_df <- 
  fake_coordinates %>% 
  dplyr::mutate(
    population = population_buffers[[2]],
    population_trainaccess = population_access_buffers[[2]],
    share_access = population_access_buffers[[2]] / population_buffers[[2]]
)

# Summary of the new data
summary(linked_df)
##           geometry   
##  POINT        :1000  
##  epsg:3035    :   0  
##  +proj=laea...:   0  
##                      
##                      
##                      
##      id_2          
##  Length:1000       
##  Class :character  
##  Mode  :character  
##                    
##                    
##                    
##    population   
##  Min.   :18.71  
##  1st Qu.:22.20  
##  Median :28.78  
##  Mean   :28.42  
##  3rd Qu.:33.67  
##  Max.   :41.75  
##  population_trainaccess
##  Min.   : 3.409        
##  1st Qu.: 5.301        
##  Median : 8.328        
##  Mean   : 8.204        
##  3rd Qu.:10.704        
##  Max.   :16.084        
##   share_access   
##  Min.   :0.1698  
##  1st Qu.:0.2404  
##  Median :0.2854  
##  Mean   :0.2795  
##  3rd Qu.:0.3174  
##  Max.   :0.3879
# Mean value: 28,94%